/**
  ******************************************************************************
  * @file    gpio.c
  * @author  ashuai0110
  * @version V1.0
  * @date    2024-01-09
  * @brief   gpio驱动,适用于PIC16(L)F1788_9
  *
  ******************************************************************************
  * @attention
  *
  * Change Logs:
  * Date          Author        Notes
  * 2024-01-09    ashuai0110    完成基本内容
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "gpio.h"

/* 私有宏定义-----------------------------------------------------------------*/

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/* RC5引脚推挽输出高电平举例
    io_config_t ioConfig;
    ioConfig.mode = GPIO_MODE_OUT_PP;
    ioConfig.speed = GPIO_SPEED_HIGH;
    gpio_init(GPIO_PORTC, 5, ioConfig);
    gpio_write(GPIO_PORTC, 5, 1);
 */

/**
  * @brief  gpio初始化
  * @param  port   : 端口 @ref GPIO_PORT
  * @param  pin    : 引脚(0~7)
  * @param  config : io参数 @ref GPIO_CONFIG
  * @retval None
  */
void gpio_init(uint8_t port, uint8_t pin, io_config_t config)
{
    switch(port)
    {
        case GPIO_PORTA:
            ANSELA = BIT_RESET(ANSELA, pin);
            if(config.mode > GPIO_MODE_ANALOG_IN)
            {
                TRISA = BIT_RESET(TRISA, pin);
                if(config.mode == GPIO_MODE_OUT_PP)
                {
                    ODCONA = BIT_RESET(ODCONA, pin);
                }
                else
                {
                    ODCONA = BIT_SET(ODCONA, pin);
                }
            }
            else
            {
                TRISA = BIT_SET(TRISA, pin);
                if(config.mode == GPIO_MODE_IN)
                {
                    WPUA = BIT_RESET(WPUA, pin);
                }
                else if(config.mode == GPIO_MODE_IPU)
                {
                    WPUA = BIT_SET(WPUA, pin);
                }
                else
                {
                    ANSELA = BIT_SET(ANSELA, pin);
                }
            }
            if(config.speed == GPIO_SPEED_HIGH)
            {
                SLRCONA = BIT_RESET(SLRCONA, pin);
            }
            else
            {
                SLRCONA = BIT_SET(SLRCONA, pin);
            }
            break;
        case GPIO_PORTB:
            ANSELB = BIT_RESET(ANSELB, pin);
            if(config.mode > GPIO_MODE_ANALOG_IN)
            {
                TRISB = BIT_RESET(TRISB, pin);
                if(config.mode == GPIO_MODE_OUT_PP)
                {
                    ODCONB = BIT_RESET(ODCONB, pin);
                }
                else
                {
                    ODCONB = BIT_SET(ODCONB, pin);
                }
            }
            else
            {
                TRISB = BIT_SET(TRISB, pin);
                if(config.mode == GPIO_MODE_IN)
                {
                    WPUB = BIT_RESET(WPUB, pin);
                }
                else if(config.mode == GPIO_MODE_IPU)
                {
                    WPUB = BIT_SET(WPUB, pin);
                }
                else
                {
                    ANSELB = BIT_SET(ANSELB, pin);
                }
            }
            if(config.speed == GPIO_SPEED_HIGH)
            {
                SLRCONB = BIT_RESET(SLRCONB, pin);
            }
            else
            {
                SLRCONB = BIT_SET(SLRCONB, pin);
            }
            break;
        case GPIO_PORTC:
            ANSELC = BIT_RESET(ANSELC, pin);
            if(config.mode > GPIO_MODE_ANALOG_IN)
            {
                TRISC = BIT_RESET(TRISC, pin);
                if(config.mode == GPIO_MODE_OUT_PP)
                {
                    ODCONC = BIT_RESET(ODCONC, pin);
                }
                else
                {
                    ODCONC = BIT_SET(ODCONC, pin);
                }
            }
            else
            {
                TRISC = BIT_SET(TRISC, pin);
                if(config.mode == GPIO_MODE_IN)
                {
                    WPUC = BIT_RESET(WPUC, pin);
                }
                else if(config.mode == GPIO_MODE_IPU)
                {
                    WPUC = BIT_SET(WPUC, pin);
                }
                else
                {
                    ANSELC = BIT_SET(ANSELC, pin);
                }
            }
            if(config.speed == GPIO_SPEED_HIGH)
            {
                SLRCONC = BIT_RESET(SLRCONC, pin);
            }
            else
            {
                SLRCONC = BIT_SET(SLRCONC, pin);
            }
            break;
#if (MCU_VERSION == MCU_PIC16F1789)
        case GPIO_PORTD:
            ANSELD = BIT_RESET(ANSELD, pin);
            if(config.mode > GPIO_MODE_ANALOG_IN)
            {
                TRISD = BIT_RESET(TRISD, pin);
                if(config.mode == GPIO_MODE_OUT_PP)
                {
                    ODCOND = BIT_RESET(ODCOND, pin);
                }
                else
                {
                    ODCOND = BIT_SET(ODCOND, pin);
                }
            }
            else
            {
                TRISD = BIT_SET(TRISD, pin);
                if(config.mode == GPIO_MODE_IN)
                {
                    WPUD = BIT_RESET(WPUD, pin);
                }
                else if(config.mode == GPIO_MODE_IPU)
                {
                    WPUD = BIT_SET(WPUD, pin);
                }
                else
                {
                    ANSELD = BIT_SET(ANSELD, pin);
                }
            }
            if(config.speed == GPIO_SPEED_HIGH)
            {
                SLRCOND = BIT_RESET(SLRCOND, pin);
            }
            else
            {
                SLRCOND = BIT_SET(SLRCOND, pin);
            }
            break;
#endif
        case GPIO_PORTE:
//            ANSELE = BIT_RESET(ANSELE, pin);
            if(config.mode > GPIO_MODE_ANALOG_IN)
            {
                TRISE = BIT_RESET(TRISE, pin);
//                if(config.mode == GPIO_MODE_OUT_PP)
//                {
//                    ODCONE = BIT_RESET(ODCONE, pin);
//                }
//                else
//                {
//                    ODCONE = BIT_SET(ODCONE, pin);
//                }
            }
            else
            {
                TRISE = BIT_SET(TRISE, pin);
                if(config.mode == GPIO_MODE_IN)
                {
                    WPUE = BIT_RESET(WPUE, pin);
                }
                else if(config.mode == GPIO_MODE_IPU)
                {
                    WPUE = BIT_SET(WPUE, pin);
                }
                else
                {
//                    ANSELE = BIT_SET(ANSELE, pin);
                }
            }
//            if(config.speed == GPIO_SPEED_HIGH)
//            {
//                SLRCONE = BIT_RESET(SLRCONE, pin);
//            }
//            else
//            {
//                SLRCONE = BIT_SET(SLRCONE, pin);
//            }
            break;
    }
}
/**
  * @brief  gpio写输出电平
  * @param  port  : 端口 @ref GPIO_PORT
  * @param  pin   : 引脚(0~7)
  * @param  level : 电平(0或1)
  * @retval None
  */
void gpio_write(uint8_t port, uint8_t pin, uint8_t level)
{
    switch(port)
    {
        case GPIO_PORTA: PORTA = (level != 0) ? BIT_SET(PORTA, pin) : BIT_RESET(PORTA, pin); break;
        case GPIO_PORTB: PORTB = (level != 0) ? BIT_SET(PORTB, pin) : BIT_RESET(PORTB, pin); break;
        case GPIO_PORTC: PORTC = (level != 0) ? BIT_SET(PORTC, pin) : BIT_RESET(PORTC, pin); break;
#if (MCU_VERSION == MCU_PIC16F1789)
        case GPIO_PORTD: PORTD = (level != 0) ? BIT_SET(PORTD, pin) : BIT_RESET(PORTD, pin); break;
#endif
        case GPIO_PORTE: PORTE = (level != 0) ? BIT_SET(PORTE, pin) : BIT_RESET(PORTE, pin); break;
    }
}
/**
  * @brief  gpio读输入电平
  * @param  port  : 端口 @ref GPIO_PORT
  * @param  pin   : 引脚(0~7)
  * @retval 电平(0或1)
  */
uint8_t gpio_read(uint8_t port, uint8_t pin)
{
    uint8_t level;
    
    switch(port)
    {
        case GPIO_PORTA: level = BIT_READ(PORTA, pin); break;
        case GPIO_PORTB: level = BIT_READ(PORTB, pin); break;
        case GPIO_PORTC: level = BIT_READ(PORTC, pin); break;
#if (MCU_VERSION == MCU_PIC16F1789)
        case GPIO_PORTD: level = BIT_READ(PORTD, pin); break;
#endif
        case GPIO_PORTE: level = BIT_READ(PORTE, pin); break;
    }
    level = (level > 0) ? 1u : 0u;
    
    return level;
}
/**
  * @brief  gpio输出电平翻转
  * @param  port  : 端口 @ref GPIO_PORT
  * @param  pin   : 引脚(0~7)
  * @retval None
  */
void gpio_toggle(uint8_t port, uint8_t pin)
{
    switch(port)
    {
        case GPIO_PORTA: PORTA = BIT_TOGGLE(PORTA, pin); break;
        case GPIO_PORTB: PORTB = BIT_TOGGLE(PORTB, pin); break;
        case GPIO_PORTC: PORTC = BIT_TOGGLE(PORTC, pin); break;
#if (MCU_VERSION == MCU_PIC16F1789)
        case GPIO_PORTD: PORTD = BIT_TOGGLE(PORTD, pin); break;
#endif
        case GPIO_PORTE: PORTE = BIT_TOGGLE(PORTE, pin); break;
    }
}

